module vga_dirve (
    input logic clk,            // 系统时钟
    input logic rst_n,          // 复位
    input logic [23:0] rgb_data, // 16位RGB对应值

    output logic vga_clk,    // vga时钟 25M
    output logic h_sync,     // 行同步信号
    output logic v_sync,     // 场同步信号
    output logic [11:0] addr_h, // 行地址
    output logic [11:0] addr_v,  // 列地址
    output logic [7:0] rgb_r,  // 红基色
    output logic [7:0] rgb_g,  // 绿基色
    output logic [7:0] rgb_b  // 蓝基色
);

// 640 * 480 60HZ
localparam int H_FRONT = 16; // 行同步前沿信号周期长
localparam int H_SYNC = 96;  // 行同步信号周期长
localparam int H_BLACK = 48; // 行同步后沿信号周期长
localparam int H_ACT = 640;   // 行显示周期长
localparam int V_FRONT = 11; // 场同步前沿信号周期长
localparam int V_SYNC = 2;   // 场同步信号周期长
localparam int V_BLACK = 31; // 场同步后沿信号周期长
localparam int V_ACT = 480;  // 场显示周期长

// 800 * 600 72HZ (已注释，使用640*480)
// ...

localparam int H_TOTAL = H_FRONT + H_SYNC + H_BLACK + H_ACT; // 行周期
localparam int V_TOTAL = V_FRONT + V_SYNC + V_BLACK + V_ACT; // 列周期

logic [11:0] cnt_h; // 行计数器
logic [11:0] cnt_v; // 场计数器
logic [23:0] rgb;  // 对应显示颜色值

// 对应计数器开始、结束、计数信号
logic flag_enable_cnt_h, flag_clear_cnt_h, flag_enable_cnt_v, flag_clear_cnt_v, flag_add_cnt_v, valid_area;

// 25M时钟 行周期*场周期*刷新率 = 800 * 525* 60
logic clk_25;
// 50M时钟 1040 * 666 * 72
// ...

// PLL实例化生成时钟
pll pll_inst (
    .areset(~rst_n),
    .inclk0(clk),
    .c0(clk_50), // 50M
    .c1(clk_25)  // 25M
);

// 根据不同分配率选择不同频率时钟
assign vga_clk = clk_25;

// 行计数
always_ff @(posedge vga_clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_h <= 0;
    end else if (flag_enable_cnt_h) begin
        cnt_h <= flag_clear_cnt_h ? 0 : cnt_h + 1;
    end
end

// 行同步信号
always_ff @(posedge vga_clk or negedge rst_n) begin
    if (!rst_n) begin
        h_sync <= 0;
    end else if (cnt_h == H_SYNC - 1) begin
        h_sync <= 1;
    end else if (flag_clear_cnt_h) begin
        h_sync <= 0;
    end
end

// 场计数
always_ff @(posedge vga_clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_v <= 0;
    end else if (flag_enable_cnt_v) begin
        cnt_v <= flag_clear_cnt_v ? 0 : cnt_v + flag_add_cnt_v;
    end
end

// 场同步信号
always_ff @(posedge vga_clk or negedge rst_n) begin
    if (!rst_n) begin
        v_sync <= 0;
    end else if (cnt_v == V_SYNC - 1) begin
        v_sync <= 1;
    end else if (flag_clear_cnt_v) begin
        v_sync <= 0;
    end
end

// 对应有效区域行地址 1-640
always_ff @(posedge vga_clk or negedge rst_n) begin
    if (!rst_n) begin
        addr_h <= 0;
    end else if (valid_area) begin
        addr_h <= cnt_h - H_SYNC - H_BLACK + 1;
    end
end

// 对应有效区域列地址 1-480
always_ff @(posedge vga_clk or negedge rst_n) begin
    if (!rst_n) begin
        addr_v <= 0;
    end else if (valid_area) begin
        addr_v <= cnt_v - V_SYNC - V_BLACK + 1;
    end
end

// 有效显示区域
assign valid_area = cnt_h >= H_SYNC + H_BLACK && cnt_h <= H_SYNC + H_BLACK + H_ACT &&
                    cnt_v >= V_SYNC + V_BLACK && cnt_v <= V_SYNC + V_BLACK + V_ACT;

// 显示颜色
always_ff @(posedge vga_clk or negedge rst_n) begin
    if (!rst_n) begin
        rgb <= 24'b0;
    end else if (valid_area) begin
        rgb <= rgb_data;
    end
end

assign rgb_r = rgb[23:16];
assign rgb_g = rgb[15:8];
assign rgb_b = rgb[7:0];

endmodule // vga_dirve





